
#include "nane/CodecSystem/Sound/WAV/WAVSoundDecoder.h"
#include "nane/core/IO.h"

#include <algorithm>

namespace nane 
{
    ////////////////////////////////////////////////////////////////////////////////////////////////
    static const uint32 RIFF_SIGNATURE = 0x46464952;
    static const uint32 WAVE_SIGNATURE = 0x45564157;
    static const uint32 FMT_SIGNATURE = 0x20746d66;
    static const uint32 DATA_SIGNATURE = 0x61746164;
    ////////////////////////////////////////////////////////////////////////////////////////////////
    WAVSoundDecoder::WAVSoundDecoder()
        : m_dataSize( 0 )
        , m_channels( 0 )
        , m_frequency( 0 )
        , m_bitsPerSample( 0 )
        , m_bytesRead( 0 )
    {
        
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
    WAVSoundDecoder::~WAVSoundDecoder()
    {
        
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
    bool WAVSoundDecoder::Initialize( IInputRef* _input )
    {
        uint32 signature = 0;
        IO<IOUnsafe>::Read(_input, &signature);
        if( signature != RIFF_SIGNATURE )
        {
            return false;
        }
        
        uint32 chunkSize;
        IO<IOUnsafe>::Read(_input, &chunkSize);
        IO<IOUnsafe>::Read(_input, &signature);
        
        if( signature != WAVE_SIGNATURE )
        {
            return false;
        }
        
        IO<IOUnsafe>::Read(_input, &signature);
        
        if( signature != FMT_SIGNATURE )
        {
            return false;
        }
        
        uint32 fmtSize = 0;
        IO<IOUnsafe>::Read(_input, &fmtSize);
        
        uint16 format = 0;
        IO<IOUnsafe>::Read(_input, &format);
        
        if( format != 1 )       // only PCM supported
        {
            return false;
        }
        
        IO<IOUnsafe>::Read(_input, &m_channels);
        IO<IOUnsafe>::Read(_input, &m_frequency);
        uint32 byteRate = 0;
        IO<IOUnsafe>::Read(_input, &byteRate);
        uint16 blockAlign = 0;
        IO<IOUnsafe>::Read(_input, &blockAlign);
        IO<IOUnsafe>::Read(_input, &m_bitsPerSample);
        
        IO<IOUnsafe>::Read(_input, &signature);
        if( signature != DATA_SIGNATURE )
        {
            return false;
        }
        IO<IOUnsafe>::Read(_input, &m_dataSize);
        m_inputPtr = InputPtr(_input);
        return true;
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
    void WAVSoundDecoder::Shutdown()
    {
        m_inputPtr = NullPtr;
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
    uint32 WAVSoundDecoder::GetFrequency()
    {
        return m_frequency;
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
    uint16 WAVSoundDecoder::GetChannels()
    {
        return m_channels;
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
    uint16 WAVSoundDecoder::GetBitsPerSample()
    {
        return m_bitsPerSample;
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
    uint32 WAVSoundDecoder::GetLengthInBytes()
    {
        return m_dataSize;
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
    uint32 WAVSoundDecoder::Read( byte* _buffer, uint32 _count )
    {
        uint32 clampedCount = std::min(_count, m_dataSize - m_bytesRead);
        uint32 bytesRead = m_inputPtr->Read(_buffer, clampedCount);
        m_bytesRead += bytesRead;
        return bytesRead;
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
}   // namespace nane
